package com.iplant.ams.serviceImpl.dao.ams;

import com.iplant.ams.service.po.ams.AMSPurchaseOrderItem;
import com.iplant.ams.service.po.ams.AMSPurchaseRequest;
import com.iplant.ams.service.po.ams.AMSReceiveGoodsItem;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.ServiceResult;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.general.CalendarTool;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.basic.service.po.bms.BMSEmployee;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

public class AMSReceiveGoodsItemDAO extends BaseDAO {

    private static Logger logger = LoggerFactory.getLogger(AMSReceiveGoodsItemDAO.class);

    private static AMSReceiveGoodsItemDAO Instance = null;

    public static AMSReceiveGoodsItemDAO getInstance() {
        if (Instance == null) {
            Instance = new AMSReceiveGoodsItemDAO();
        }
        return Instance;
    }

    /**
     * 新增或更新
     *
     * @param wLoginUser
     * @param wItem
     * @param wErrorCode
     * @return
     */
    public int Update(BMSEmployee wLoginUser, AMSReceiveGoodsItem wItem, OutResult<Integer> wErrorCode) {
        int wResult = 0;

        try {
            if (wItem == null) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            if (wItem.getID() > 0) {
                // 如果是更新，则需要回写采购单项的到货数
                if (wItem.getReceiveQuantity() <= 0) {
                    wErrorCode.set(ExceptionTypes.Parameter.getValue());
                    return wResult;
                }
                // 已到货数量 + 本次到货数量 不能超过采购数量
                if (wItem.getReceivedTotal() + wItem.getReceiveQuantity() > wItem.getPurchaseQuantity()) {
                    wErrorCode.set(ExceptionTypes.DataInvalid.getValue());
                    return wResult;
                }

                int wUpdateResult = AMSPurchaseOrderItemDAO.getInstance().UpdateReceiveQuantity(
                        wLoginUser, wItem.getOrderItemID(), wItem.ReceiveQuantity, wErrorCode);
                if (wErrorCode.Result != 0) {
                    return wResult;
                }
            }

            wItem.setUserInfo(wLoginUser);
            wResult = this.UpdatePo(wLoginUser, wItem, wErrorCode);
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            logger.error(ex.toString());
        }

        return wResult;
    }

    /**
     * 单条删除
     *
     * @param wLoginUser
     * @param wItem
     * @param wErrorCode
     * @return
     */
    public ServiceResult<Integer> Delete(BMSEmployee wLoginUser, AMSReceiveGoodsItem wItem, OutResult<Integer> wErrorCode) {
        ServiceResult<Integer> wResult = new ServiceResult<>();

        try {
            if (wItem == null || wItem.getID() <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

//            this.DeletePO(wLoginUser, wItem, wErrorCode);

            // 需要执行2步：1.删除收货项；2.更新采购项的已到货数量；
            List<String> wSQLList = new ArrayList<>();
            wSQLList.add(StringUtils.Format(
                    "DELETE FROM {0}.ams_receive_goods_item WHERE ID = {1} ",
                    super.getDBName(), wItem.getID()));

            // 如果收货数量>0，则需更新采购项的已到货数量
            if (wItem.getReceiveQuantity() > 0) {
                wSQLList.add(StringUtils.Format(
                        "UPDATE {0}.ams_purchase_order_item " +
                                "SET ReceiveQuantity = ReceiveQuantity - {1} WHERE ID = {2} ",
                        super.getDBName(), wItem.getReceiveQuantity(), wItem.getOrderItemID()));
            }

            int wExecuteResult = super.Execute(wSQLList);
            if (wExecuteResult<0) {
                wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            }
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            logger.error(ex.toString());
        }

        return wResult;
    }

    /**
     * 批量删除
     *
     * @param wLoginUser
     * @param wItemList
     * @param wErrorCode
     * @return
     */
    public ServiceResult<Integer> DeleteList(BMSEmployee wLoginUser, List<AMSReceiveGoodsItem> wItemList, OutResult<Integer> wErrorCode) {
        ServiceResult<Integer> wResult = new ServiceResult<Integer>(0);

        try {
            if (wItemList == null || wItemList.isEmpty()) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }
            wItemList.removeIf(p -> p.getID() <= 0);
            if (wItemList.isEmpty()) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }
            wItemList.removeIf(p -> p.getID() <= 0);
            if (wItemList.isEmpty()) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            // 组装SQL语句，先删除收货项，再更新采购订单项的已到货数量
            List<String> wSQLList = new ArrayList<>();

            // 取出ID队列
            List<Integer> wIDList = wItemList.stream().map(t -> t.getID()).collect(Collectors.toList());
            // 批量删除SQL语句
            wSQLList.add(StringUtils.Format(
                    "DELETE FROM {0}.ams_receive_goods_item WHERE ID in ({1})",
                    super.getDBName(), StringUtils.Join(",", wIDList)));

            // 分组求和，Map<采购项，本次到货数>
            Map<Integer, Integer> wIDCountMap = wItemList.stream().collect(Collectors.groupingBy(
                    t -> t.getOrderItemID(), Collectors.summingInt(t -> t.getReceiveQuantity())));

            // 剔除掉采购数为0的元素
            wIDCountMap.entrySet().removeIf(t -> t.getValue() <= 0);
            if (!wIDCountMap.isEmpty()) {
                // 组装SQL语句
                StringBuilder wStringWhenThen = new StringBuilder();
                wIDCountMap.forEach((k, v) -> {
                    wStringWhenThen.append(StringUtils.Format(" WHEN {0} THEN {1} ", k, v));
                });
                wSQLList.add(StringUtils.Format(
                        "UPDATE {0}.ams_purchase_order_item SET ReceiveQuantity = ReceiveQuantity - CASE ID {1} END WHERE ID in ({2}) ",
                        super.getDBName(), wStringWhenThen.toString(), StringUtils.Join(",", wIDCountMap.keySet())));
            }

            // 批量执行SQL语句，失败则回滚
            int wExecuteResult = super.Execute(wSQLList);
            if (wExecuteResult<0) {
                wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            }
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            logger.error(ex.toString());
        }

        return wResult;
    }

    /**
     * 用收货单ID查询收货清单
     *
     * @param wLoginUser
     * @param wParentID
     * @param wErrorCode
     * @return
     */
    public List<AMSReceiveGoodsItem> SelectListByParentID(BMSEmployee wLoginUser, int wParentID, OutResult<Integer> wErrorCode) {
        List<AMSReceiveGoodsItem> wResultList = new ArrayList<>();

        try {
            if (wParentID <= 0) {
                return wResultList;
            }

//            wResultList=this.SelectList();
        } catch (Exception ex) {
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            logger.error(ex.toString());
        }

        return wResultList;
    }

    /**
     * 条件查询集合
     *
     * @param wLoginUser
     * @param wIDs
     * @param wName
     * @param wCode
     * @param wCreatorID
     * @param wActive
     * @param wStateIDList
     * @param wParentID    收货单ID
     * @param wOrderItemID
     * @param wStartTime
     * @param wEndTime
     * @param wPagination
     * @param wErrorCode
     * @return
     */
    public List<AMSReceiveGoodsItem> SelectList(BMSEmployee wLoginUser, List<Integer> wIDs, String wName, String wCode,
            int wCreatorID, int wActive, List<Integer> wStateIDList, int wParentID, int wOrderItemID,
            Calendar wStartTime, Calendar wEndTime, Pagination wPagination, OutResult<Integer> wErrorCode) {
        List<AMSReceiveGoodsItem> wResultList = new ArrayList<>();

        try {
            // ID List
            if (wIDs == null) {
                wIDs = new ArrayList<>();
            }
            wIDs.removeIf(p -> p <= 0);

            // StateID List
            if (wStateIDList == null) {
                wStateIDList = new ArrayList<>();
            }

            // 时间的处理
            Calendar wBaseTime = CalendarTool.getBasicDate();
            wBaseTime.set(2000, 1, 1);
            if (wStartTime == null || wStartTime.compareTo(wBaseTime) < 0) {
                wStartTime = wBaseTime;
            }
            if (wEndTime == null || wEndTime.compareTo(wBaseTime) < 0) {
                wEndTime = wBaseTime;
            }
            if (wStartTime.compareTo(wEndTime) > 0) {
                return wResultList;
            }

            String wSQL = StringUtils.Format(
                    "SELECT t1.*, t2.PurchaseQuantity, t2.ReceiveQuantity AS ReceivedTotal, t3.Name AS AssetName, t3.AssetModel, t3.AssetUnit " +
                            "FROM {0}.ams_receive_goods_item t1 " +
                            "LEFT JOIN {0}.ams_purchase_order_item t2 ON t1.OrderItemID = t2.ID " +
                            "LEFT JOIN {0}.ams_asset_standard_model t3 ON t2.AssetStandardModelID = t3.ID " +
                            "WHERE 1=1 " +
                            " AND (:ID = '''' or t1.ID IN (''{1}'')) " +
                            " AND (:Name = '''' OR t1.Name like :Name) " +
                            " AND (:Code = '''' OR t1.Code like :Code) " +
                            " AND (:CreatorID <= 0 OR t1.CreatorID = :CreatorID ) " +
                            " AND (:Active < 0 OR t1.Active = :Active) " +
                            " AND (:StartTime <= str_to_date(''2010-01-01'', ''%Y-%m-%d'') OR :StartTime <= t1.CreateTime) " +
                            " AND (:EndTime <= str_to_date(''2010-01-01'', ''%Y-%m-%d'') OR :EndTime >= t1.CreateTime) " +
                            " AND (:Status = '''' OR t1.CurrentStatus IN (''{2}'')) " +
                            " AND (:ReceiveID =< 0 OR t1.ReceiveID = :ReceiveID) " +
                            " AND (:OrderItemID <= 0 OR t1.OrderItemID = :OrderItemID) ",
                    super.getDBName(), StringUtils.Join("','", wIDs), StringUtils.Join("','", wStateIDList));

            Map<String, Object> wParamMap = new HashMap<>();
            wParamMap.put("ID", StringUtils.Join(",", wIDs));
            wParamMap.put("Name", StringUtils.isEmpty(wName) ? "" : ("%" + wName + "%"));
            wParamMap.put("Code", StringUtils.isEmpty(wCode) ? "" : ("%" + wCode + "%"));
            wParamMap.put("CreatorID", wCreatorID);
            wParamMap.put("Active", wActive);
            wParamMap.put("Status", StringUtils.Join(",", wStateIDList));
            wParamMap.put("StartTime", wStartTime);
            wParamMap.put("EndTime", wEndTime);
            wParamMap.put("ReceiveID", wParentID);
            wParamMap.put("OrderItemID", wOrderItemID);

            wSQL = this.DMLChange(wSQL);

            wResultList = this.QueryForList(wSQL, wParamMap, wPagination, AMSReceiveGoodsItem.class);
        } catch (Exception ex) {
            wErrorCode.set(Integer.valueOf(ExceptionTypes.DBSQL.getValue()));
            logger.error(ex.toString());
        }

        return wResultList;
    }
}
